<template>
    <tnxel-submit-form ref="form" :model="model" inline>
        <div class="flex-v-center">
            <el-form-item label="abstract">
                <tnxel-enum-view type="Boolean" :item-key="String(clazz.abstractClass)"/>
            </el-form-item>
            <el-form-item label="父类" v-if="clazz.superClassId">
                <ClassNameView :app="app"
                    :class-id="clazz.superClassId"
                    @open-class="$emit('open-class', $event)"
                    @open-update="$emit('open-update', clazz)"
                />
            </el-form-item>
            <el-form-item label="泛型具化" v-if="clazz.instantiatedGenericTypes?.length">
                <GenericTypeDeclare v-model="model.instantiatedGenericTypes"
                    :app="app"
                    :updatable="false"
                />
            </el-form-item>
            <el-form-item label=" " class="flex-1 me-0">
                <div class="w-100 flex-v-center justify-content-end">
                    <tnxel-button type="primary"
                        icon="fa-regular fa-floppy-disk"
                        :loading="saving"
                        :disabled="app.dependencyInitializing"
                        disabled-tip="依赖库加载中，需加载完毕后才可保存"
                        @click="toSave"
                    >
                        保存 (Ctrl+S)
                    </tnxel-button>
                    <tnxel-button type="default"
                        class="ms-2"
                        icon="bi bi-code-slash"
                        :key="clazz.modified"
                        :disabled="app.dependencyInitializing || clazz.modified"
                        :disabled-tip="app.dependencyInitializing ? '依赖库加载中，需加载完毕后才可生成代码' : '已改动，需保存后才可生成代码'"
                        @click="toGenerateCode"
                    >
                        生成代码
                    </tnxel-button>
                </div>
            </el-form-item>
        </div>
        <el-form-item label="属性集" class="w-100 me-0 mb-1" label-width="58px">
            <div class="flex-v-center w-100 justify-content-end">
                <div class="row-derived text-secondary px-2 ms-2"
                    v-if="model.properties?.some(p => p.derived)">
                    派生属性
                </div>
            </div>
        </el-form-item>
        <tnxel-edit-table
            :data="model.properties"
            add-text="添加属性"
            :new-row="newProperty"
            :row-class-name="rowClassName"
            :rules="propertyRules"
            sortable
        >
            <el-table-column label="序号" type="index" align="center" width="60">
                <template #default="{ row, $index }">
                    <ColorableIndex :index="$index" v-model:color="row.color"/>
                </template>
            </el-table-column>
            <el-table-column label="显示名称" prop="caption">
                <template #default="{ row }">
                    <el-input v-model="row.caption"/>
                </template>
            </el-table-column>
            <el-table-column label="属性名" prop="name">
                <template #default="{ row }">
                    <el-input v-model="row.name"
                        :disabled="row.primary && TypeKind.UNITY.equals(clazz.kind)"/>
                </template>
            </el-table-column>
            <el-table-column label="属性类型" prop="type">
                <template #default="{ row }">
                    <LogicTypeSelect class="w-100"
                        v-model="row.typeId"
                        :app="app"
                        :kind="clazz.kind"
                        :primary="row.primary"
                        :key="model.properties.length"
                        @change="onLogicTypeChange(row)"/>
                </template>
            </el-table-column>
            <el-table-column label="泛型" prop="genericTypes">
                <template #default="{ row }">
                    <GenericTypeSpecify v-model="row.genericTypes"
                        :app="app"
                        :logic-type="row.typeId"
                        :title="'属性 ' + row.name + ' 泛型设定'"
                    />
                </template>
            </el-table-column>
            <el-table-column label="数组" prop="arrayed" align="center" width="100">
                <template #default="{ row }">
                    <ArrayedSelect v-model="row.arrayed" :property="row"/>
                </template>
            </el-table-column>
            <el-table-column prop="derived" align="center" width="120">
                <template #header>
                    <span>性质</span>
                    <el-tooltip
                        content="派生属性是基于其它属性的值动态计算得出的属性，其计算算法在生成代码后手工实现"
                        placement="top"
                    >
                        <tnxel-icon value="QuestionFilled" class="ms-1"/>
                    </el-tooltip>
                </template>
                <template #default="{ row }">
                    <tnxel-select v-model="row.derived" :items="[{
                        value: false,
                        text: '普通',
                    }, {
                        value: true,
                        text: '派生',
                    }]"/>
                </template>
            </el-table-column>
            <el-table-column prop="manualInput" align="center" width="120">
                <template #header>
                    <span>高级设置</span>
                    <el-tooltip placement="top" content="由用户填写的字段不允许输入特殊字符">
                        <tnxel-icon class="ms-1" value="QuestionFilled"/>
                    </el-tooltip>
                </template>
                <template #default="{ row }">
                    <div class="advanced-setting"
                        :class="{'is-disabled': app.dependencyInitializing}"
                    >
                        <!-- 用户填写 -->
                        <div class="col">
                            <tnxel-button
                                tooltip="点击切换"
                                :tooltip-show-after="600"
                                type="primary"
                                link
                                :icon="row.manualInput ? 'UserFilled' : 'User'"
                                :title="row.manualInput ? '由用户填写' : '非用户填写'"
                                @click="row.manualInput = !row.manualInput"
                                v-if="isManualInputEnabled(row)"
                            />
                        </div>
                        <!-- 行政区划 -->
                        <div class="col">
                            <tnxel-button
                                tooltip="点击切换"
                                :tooltip-show-after="600"
                                type="primary"
                                link
                                :icon="row.regional ? 'bi bi-pin-map-fill' : 'bi bi-pin-map'"
                                :title="row.regional ? '行政区划字段' : '非行政区划字段'"
                                @click="row.regional = !row.regional"
                                v-if="isRegionalEnabled(row)"
                            />
                        </div>
                    </div>
                </template>
            </el-table-column>
        </tnxel-edit-table>
    </tnxel-submit-form>
</template>

<script>
import tnx from '@/tnx.js';
import TypeKind from '@/logic/modeling/enums/TypeKind.js';
import ModelingApp from '@/logic/modeling/entity/ModelingApp.js';
import ValueClass from '@/logic/modeling/entity/ValueClass.js';
import DomainProperty from '@/logic/modeling/entity/DomainProperty.js';
import {STRING_CLASS_NAME} from '@/logic/modeling/util/dependency-lib-jdk.js';

import ColorableIndex from './components/ColorableIndex.vue';
import ClassNameView from './components/ClassNameView.vue';
import LogicTypeSelect from './components/LogicTypeSelect.vue';
import GenericTypeSpecify from './components/GenericTypeSpecify.vue';
import GenericTypeDeclare from './components/GenericTypeDeclare.vue';
import ArrayedSelect from './components/ArrayedSelect.vue';
import generateCode from './generate-code.vue';

export default {
    name: 'ValueClassEdit',
    components: {
        ColorableIndex,
        ClassNameView,
        LogicTypeSelect,
        GenericTypeSpecify,
        GenericTypeDeclare,
        ArrayedSelect,
    },
    props: {
        app: {
            type: ModelingApp,
            required: true
        },
        clazz: {
            type: ValueClass,
            required: true,
        },
        save: {
            type: Function,
            required: true,
        },
        active: {
            type: Boolean,
            required: true,
        },
    },
    emits: ['open-setting', 'open-class', 'open-update'],
    data() {
        let properties = [];
        for (let property of this.clazz.properties) {
            let refClass = this.app.findClass(property.typeId);
            property.refKind = refClass?.getKind();
            properties.push(property);
        }
        return {
            TypeKind: TypeKind,
            model: {
                instantiatedGenericTypes: this.clazz.instantiatedGenericTypes ? this.clazz.instantiatedGenericTypes.map(
                    type => type.clone()) : [],
                properties: properties,
            },
            propertyRules: {
                caption: [tnx.app.validator.manualInputRule],
                name: [tnx.app.validator.requiredRule, tnx.app.validator.symbolRule],
            },
            lengthDisabled: [],
            scaleDisabled: [],
            saving: false,
        };
    },
    computed: {
        STRING_CLASS_NAME() {
            return STRING_CLASS_NAME;
        }
    },
    watch: {
        active() {
            if (this.active) {
                window.addEventListener('keydown', this.onKeydown);
            } else {
                window.removeEventListener('keydown', this.onKeydown);
            }
        },
    },
    created() {
        tnx.deepWatch(this, this.model, (newValue, oldValue, path) => {
            if (!path.endsWith('.refKind')) {
                this.clazz.modified = true;
                // console.info(
                //     path + ': ' + tnx.util.string.toJson(oldValue) + ' -> ' + tnx.util.string.toJson(newValue));
            }
        });
    },
    mounted() {
        if (this.app.dependencyInitializing) {
            this.$refs.form.disable();
        } else {
            window.addEventListener('keydown', this.onKeydown);
        }
    },
    unmounted() {
        this.clazz.modified = false;
        window.removeEventListener('keydown', this.onKeydown);
    },
    methods: {
        newProperty() {
            let ordinal = this.model.properties.length + 1;
            return DomainProperty.of({
                name: 'property' + ordinal,
                typeId: STRING_CLASS_NAME,
            });
        },
        rowClassName({row}) {
            if (row.derived) {
                return 'row-derived';
            }
            return undefined;
        },
        onLogicTypeChange(row) {
            let refClass = this.app.findClass(row.typeId, true);
            row.refKind = refClass?.getKind();
        },
        isManualInputEnabled(row) {
            return row.typeId === STRING_CLASS_NAME && !row.arrayed && !row.regional;
        },
        isRegionalEnabled(row) {
            return row.typeId === STRING_CLASS_NAME && !row.arrayed && !row.manualInput;
        },
        toSave() {
            tnx.showLoading();
            this.doSave(() => {
                tnx.closeLoading();
            });
        },
        doSave(callback) {
            let model = Object.assign({}, this.model, {
                type: this.clazz.kind,
                packageName: this.clazz.packageName,
                simpleName: this.clazz.simpleName,
            });
            this.saving = true;
            this.save(this.clazz.id, this.app, model, success => {
                setTimeout(() => {
                    if (success) {
                        this.clazz.modified = false;
                    }
                    this.saving = false;
                    if (typeof callback === 'function') {
                        callback();
                    }
                }, 300);
            });
        },
        onKeydown(event) {
            if (event.ctrlKey && event.key.toLowerCase() === 's') {
                this.toSave();
            }
        },
        toGenerateCode() {
            if (!this.clazz.modified) {
                tnx.open(generateCode, {
                    app: this.app,
                    clazz: this.clazz,
                });
            }
        },
    }
}
</script>

<style lang="scss" scoped>
:deep(.tnxel-edit-table-container) {

    .generic-type-select {
        .el-button {
            border-left-color: var(--el-border-color-lighter);
        }
    }

    .advanced-setting {
        display: flex;
        justify-content: center;
        width: fit-content;

        .col {
            width: 24px;
        }
    }

}
</style>
